﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Web;
using System.Web.UI;
using TA.JSON;
using TA.Turbo.Controls;
namespace TA.Turbo
{
	public partial class TPage
	{
		#region STATIC
		#region Properties
		/// <summary>
		/// Returns the current <see cref="TPage"/>.
		/// </summary>
		public static TPage Current
		{
			get
			{
				if (HttpContext.Current == null) return null;
				//if (!(HttpContext.Current.Handler is TPage))
				//throw new InvalidOperationException("Current handler is not an instance of TurboPage. Please derive the page object from TurboPage.");
				return HttpContext.Current.Handler as TPage;
			}
		}
		/// <summary>
		/// Returns the current post back's PostScenario.
		/// </summary>
		public static PostScenario Scenario
		{
			get
			{
				return Current.CurrentScenario;
			}
		}
		#endregion
		#endregion
		#region PROPS
		#region INPUT
		/// <summary>
		/// True if current post back is a Turbo post. Note: if the PostScenario's Clean property is set to true, this property will return false.
		/// </summary>
		public bool IsTurboPost
		{
			get
			{
				//return string.Equals(Request["__TURBO"], "1");
				return !string.IsNullOrEmpty(Request["__T"]) && !string.IsNullOrEmpty(Request["__N"]);
			}
		}
		/// <summary>
		/// True if current post back is a form post. This is usually the case if JavaScript is not enabled/supported by the browser or if the application uses custom logic for post backs.
		/// </summary>
		public bool IsFormPost
		{
			get
			{
				return !IsTurboPost && this.Request.Form.Count > 0;
			}
		}
		/// <summary>
		/// Gets the current scenario which is determined from the <see cref="EventTarget"/> and <see cref="EventName"/>.
		/// </summary>
		public PostScenario CurrentScenario
		{
			get
			{
				if (_currentScenario == null)
				{
					if (IsTurboPost || this.IsFormPost)
					{
						if (this.EventTarget != null)
						{
							PostScenario ps = this.EventTarget.GetCurrentScenario(this.EventName, this.EventArgument);
							if (ps != null)
							{
								this._currentScenario = new CurrentPostScenario(ps);
							}
						}
					}
				}
				return _currentScenario;
			}
		}
		/// <summary>
		/// Gets the array of validators applied to the current request.
		/// </summary>
		public BaseValidator[] CurrentValidators
		{
			get
			{
				if (!IsPostBack) throw new InvalidOperationException("Can't get CurrentValidators if there is no post back (because there is nothing to validate).");
				if (_currentValidators == null)
				{
					List<BaseValidator> res = new List<BaseValidator>();
					if (this.CurrentScenario == null || this.CurrentScenario.ValidationGroupList.Count == 0)
					{
						foreach (BaseValidator val in this.Validators)
						{
							if (val.Enabled)
								res.Add(val);
						}
					}
					else
					{
						foreach (BaseValidator val in this.Validators)
						{
							if (
								val.Enabled &&
								(
									string.IsNullOrEmpty(val.Group)
									||
									this.CurrentScenario.ValidationGroupList.Contains(val.Group)
								))
								res.Add(val);
						}
					}
					_currentValidators = res.ToArray();
				}
				return _currentValidators;
			}
		}
		/// <summary>
		/// Gets true if the current request was validated, otherwise false.
		/// </summary>
		public new bool IsValid
		{
			get
			{
				if (_isValid == null)
				{
					_isValid = true;
					if (NeedValidation)
					{
						_isValid = Validate();
					}
				}
				return _isValid.Value;
			}
		}
		/// <summary>
		/// Gets the target control of the current request.
		/// </summary>
		public IEventHandler EventTarget
		{
			get
			{
				if (!this.IsTurboPost && !this.IsFormPost)
					throw new TurboRequestException("EventTarget not available during a non-post request.");

				if (this._eventTarget == null)
				{
					if (this.IsTurboPost)
					{
						string eventTargetId = Request["__T"];
						if (!string.IsNullOrEmpty(eventTargetId))
						{
							Control ctl = this.FindControl(eventTargetId);
							if (ctl.Page != null) // checking to make sure this control hadn't been removed from the control tree
							{
								this._eventTarget = ctl as IEventHandler;
							}
						}
					}
					else if (this.IsFormPost)
					{
						foreach (TControl bc in this._controls.Values)
						{
							if (bc is BaseCommandControl)
							{
								if (this.Request.Form[bc.UniqueID] != null)
								{
									this._eventTarget = bc;
									break;
								}
							}
						}
					}
				}
				return this._eventTarget;
			}
		}
		/// <summary>
		/// Gets the event name of the current request.
		/// </summary>
		public string EventName
		{
			get
			{
				if (!this.IsTurboPost && !this.IsFormPost)
					throw new InvalidOperationException("EventName not available during non-post request.");

				if (this._eventName == null)
				{
					if (this.IsTurboPost)
					{
						this._eventName = Request["__N"];
					}
					else if (this.IsFormPost)
					{
						if (this.EventTarget != null)
						{
							object[] attrs = this.EventTarget.GetType().GetCustomAttributes(typeof(DefaultEventAttribute), true);
							if (attrs.Length > 0)
								this._eventName = ((DefaultEventAttribute)attrs[0]).Name;
						}
					}
				}
				return this._eventName;
			}
		}
		/// <summary>
		/// Gets the event argument of the current request.
		/// </summary>
		public string EventArgument
		{
			get
			{
				return this.Request["__A"];
			}
		}
		/// <summary>
		/// Gets true if JavaScript is confirmed supported and enabled on the browser; false if confirmed unsupported or disabled; and null if not yet confirmed.
		/// </summary>
		public bool? JavaScript
		{
			get
			{
				return this._javaScript;
			}
		}
		#endregion
		#region PROCESSING
		/// <summary>
		/// Set this to true to perform another load iteration. False is not a valid value (will throw).
		/// </summary>
		public bool LoadAgain
		{
			get
			{
				return _loadAgain;
			}
			set
			{
				if (!value)
					throw new ArgumentException("Can't be false.", "value");
				this._loadAgain = true;
			}
		}
		/// <summary>
		/// Gets the load iteration count, starting at 0.
		/// </summary>
		public int LoadIteration
		{
			get
			{
				if (!this.IsTurboPost)
				{
					throw new InvalidOperationException("This is not a post back. LoadIteration is not valid during non-postback requests.");
				}
				return this._loadIteration;
			}
		}
		#endregion
		#region OUTPUT
		//public AjaxResult Result
		//{
		//  get
		//  {
		//    return this._ajaxResult;
		//  }
		//}
		/// <summary>
		/// The main result to be sent back to the client. This is supposed to be used by the control handling the event.
		/// </summary>
		public object ResultMain { get; set; }
		/// <summary>
		/// The custom result to be sent back to the client. This is supposed to be used by user code which is called when a control is processing the event.
		/// </summary>
		public object ResultCustom { get; set; }
		/// <summary>
		/// The hash string to be sent back to the client. It is sent only if <see cref="PostScenario.ReturnHashString"/> is set to true on the <see cref="CurrentScenario"/>. If this property is null and <see cref="PostScenario.ReturnHashString"/> is true, it is built by polling all <see cref="IHashStringPartProvider"/>s registered with the page.
		/// </summary>
		public string ResultHashString { get; set; }
		#endregion
		/// <summary>
		/// Gets a flag which indicates if this instance of <see cref="TPage"/> is reusable for future requests.
		/// </summary>
		public new virtual bool IsReusable
		{
			get
			{
				return true;
			}
		}
		#endregion
		#region EVENTS
		/// <summary>
		/// Serializer used for ResultMain and ResultCustom. Set this for every request (during Page_Load or custom event handler).
		/// </summary>
		public event EventHandler<SerializeEventArgs> SerializeResult;
		#endregion
		#region METHODS
		/// <summary>
		/// Registers the specified scripts for execution upon processing the result of the AJAX request.
		/// </summary>
		/// <param name="key"></param>
		/// <param name="script"></param>
		/// <param name="replaceIfExists"></param>
		public void RegisterScript(string key, string script, bool replaceIfExists)
		{
			if (key == null) throw new ArgumentNullException("key");
			if (script == null) throw new ArgumentNullException("script");

			if (!this._ajaxScripts.ContainsKey(key) || replaceIfExists)
			{
				this._ajaxScripts[key] = TPage.PrepareScript(script);
			}
		}
		/// <summary>
		/// Registers a cookie which is unique for each tab in a multi-tab, shared-instance, browser.
		/// </summary>
		/// <param name="name">The name of the cookie.</param>
		/// <param name="defaultValue">The value to be set if cookie does not already exist.</param>
		/// <param name="expires">Expiration date.</param>
		/// <returns>The value of the cookie, if it is already set, or the defaultValue otherwise.</returns>
		public string UniqueCookie(string name, string defaultValue, DateTime expires)
		{
			string value = defaultValue;

			this._uniqueCookies.Add(name);
			if (Request.Cookies[name] != null && !string.IsNullOrEmpty(Request.Cookies[name].Value))
				value = Request.Cookies[name].Value;

			Response.Cookies.Add(new HttpCookie(name, value) { Expires = expires });

			return value;
		}
		/// <summary>
		/// Validates the current request.
		/// </summary>
		/// <returns></returns>
		public new bool Validate()
		{
			foreach (BaseValidator val in this.CurrentValidators)
			{
				if (val.IsServerValidated)
				{
					val.Validate();
					if (!val.IsValid)
						return false;
				}
			}
			return true;
		}
		/// <summary>
		/// Raises events.
		/// </summary>
		/// <param name="name"></param>
		/// <param name="argument"></param>
		public virtual void RaiseEvent(string name, string argument)
		{
			this.AllPageEvents[name].Raise(argument);
		}
		/// <summary>
		/// Gets the current scenario for this control using the specified event name.
		/// </summary>
		/// <param name="name"></param>
		/// <param name="argument"></param>
		/// <returns></returns>
		public PostScenario GetCurrentScenario(string name, string argument)
		{
			return this.AllPageEvents[name].PostScenario;
		}
		#endregion
	}
}